/**
 * 
 */
package com.ihome.framework.core.event.command.handler;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.ihome.framework.core.event.IHomeEventBusHandler;
import com.ihome.framework.core.event.IHomeEventBusHandler.EventBusWorkHandler;
import com.ihome.framework.core.event.command.CommandEventBusSpringBeanRegister.CommandEvent;
import com.ihome.framework.core.event.command.CommandExecutor;
import com.ihome.framework.core.event.command.buffer.CommandBuffer;
import com.ihome.framework.core.event.command.buffer.SimpleSqlCommand;
import com.ihome.framework.core.event.command.buffer.CommandBuffer.CommandDto;

/**
 * @author zww
 *
 */
public class SimpleCommandEventHandler<D extends CommandDto> extends EventBusWorkHandler<CommandEvent<D>>{

    private CommandBuffer[] buffers;

    private Map<Class<?>, CommandBuffer> fromClzCommandBuffers = new HashMap<Class<?>, CommandBuffer>();

    private CommandExecutor[] executors;

    private Map<Class<?>, CommandExecutor> fromClzCommandExecutors = new HashMap<Class<?>, CommandExecutor>();


    /* (non-Javadoc)
     * @see com.ihome.framework.core.event.IHomeEventBusHandler.EventBusWorkHandler#handler(com.ihome.framework.core.event.IHomeEventBusHandler.EventDto, boolean)
     */
    @Override
    public void handler(CommandEvent<D> event,long sequence,boolean endOfBatch) throws Exception {
        Assert.notNull(event);
        Assert.notNull(event.getCommandDto());
        
        CommandDto commandDto = event.getCommandDto();
        Class<?> fromClz = commandDto.getClass();
        if(commandDto instanceof SimpleSqlCommand){
            fromClz = ((SimpleSqlCommand)commandDto).getSimpleClass();
        }
        
        CommandBuffer buffer = findGeneralization(fromClzCommandBuffers, fromClz);
        CommandExecutor executor = findGeneralization(fromClzCommandExecutors, fromClz);

        Assert.notNull(buffer);
        Assert.notNull(executor);

        if (!buffer.hasRemaining()) {
            flushBuffer(executor,buffer);
        }
        buffer.put(event.getCommandDto());
        if (endOfBatch) {
            flushBuffer(executor,buffer);
        }
    }

    private void flushBuffer(CommandExecutor<D,CommandBuffer<D>> executor,CommandBuffer<D> buffer) {
        executor.execute(buffer);
        buffer.clear();
    }

    /* (non-Javadoc)
     * @see com.ihome.framework.core.event.IHomeEventBusHandler.EventBusWorkHandler#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();
        for (CommandBuffer commandBuffer : buffers) {
            Class<?> fromClz = IHomeEventBusHandler.getSuperClassActualTypeArguments(commandBuffer.getClass(), 0);
            fromClzCommandBuffers.put(fromClz, commandBuffer);
        }
        for (CommandExecutor commandExecutor : executors) {
            Class<?> fromClz = IHomeEventBusHandler.getSuperInterfacesActualTypeArguments(commandExecutor.getClass(), 0, 0);
            fromClzCommandExecutors.put(fromClz, commandExecutor);
        }
    }

    /* (non-Javadoc)
     * @see com.ihome.framework.core.event.IHomeEventBusHandler.EventBusWorkHandler#destroy()
     */
    @Override
    public void destroy() throws Exception {
        super.destroy();
        fromClzCommandBuffers.clear();
        fromClzCommandExecutors.clear();
        fromClzCommandBuffers = null;
        fromClzCommandExecutors = null;
    }


    /**
     * @param buffers the buffers to set
     */
    @Autowired
    public void setBuffers(CommandBuffer[] buffers) {
        this.buffers = buffers;
    }

    /**
     * @param executors the executors to set
     */
    @Autowired
    public void setExecutors(CommandExecutor[] executors) {
        this.executors = executors;
    }


    protected <T> T findGeneralization(Map<Class<?>, T> hashMap,Class<?> clz){
        for (Class<?> fromClz: hashMap.keySet()) {
            if(fromClz.isAssignableFrom(clz)){
                return hashMap.get(fromClz); 
            }
        }
        return null;
    }

    @Deprecated
    protected <T> T findGeneralizationSuperClass(T[] list,Class<?> clz) throws Exception{
        for (T t : list) {
            Class<?> fromClz = IHomeEventBusHandler.getSuperClassActualTypeArguments(t.getClass(), 0);
            if(fromClz.isAssignableFrom(clz)){
                return t;
            }
        }
        return null;
    }
    @Deprecated
    protected <T> T findGeneralizationSuperInterfaces(T[] list,Class<?> clz) throws Exception{
        for (T t : list) {
            Class<?> fromClz = IHomeEventBusHandler.getSuperInterfacesActualTypeArguments(t.getClass(), 0, 0);
            if(fromClz.isAssignableFrom(clz)){
                return t;
            }
        }
        return null;
    }

}
